// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: qiang

#pragma once

#include <memory>
#include <string>
#include <string_view>
#include <unordered_set>
#include <utility>
#include <vector>

#include "coin/proto/coin_order_enums.pb.h"
#include "coin2/exchange/base/api_base/asio_http_context.h"
#include "coin2/exchange/base/order/parser.h"
#include "coin2/exchange/base/symbology/currency.h"
#include "coin2/exchange/crypto/symbology/currency.h"
#include "coin2/exchange/crypto/symbology/product.h"

namespace coin2::exchange::crypto::order_futures {
class CryptoFuturesParser : public base::order::BaseParser {
  using JsonValue = base::order::BaseParser::JsonValue;
  using SubmitOrderResponse = base::order::BaseParser::SubmitOrderResponse;
  using ProductOrderBundle = base::order::BaseParser::ProductOrderBundle;
  using ProductFillBundle = base::order::BaseParser::ProductFillBundle;
  using AccountBalance = base::order::BaseParser::AccountBalance;
  using ProductOrderElement = base::order::BaseParser::ProductOrderElement;
  using AccountPosition = base::order::BaseParser::AccountPosition;
  using OrderErrorCode = base::order::BaseParser::OrderErrorCode;
  using OrderSubTopicId = base::order::BaseParser::OrderSubTopicId;
  using OrderSide = coin::proto::OrderSide;
  using OrderType = coin::proto::OrderType;

 public:
  const ParseResult& ParseRawMessage(const RawMessage& msg) override;
  // keep this api for accounting system
  AccountBalance ParseBalance(const JsonValue& document) override;
  AccountPosition ParsePosition(const JsonValue& doc) override;

  bool ParseRawBalance(const JsonValue& document, RawBalanceMap* raw_balance_map);

 private:
  void ParseSubmitResponse();
  void ParseCancelResponse();
  void ParseRestOpenOrders();
  void ParseRestDoneOrders();
  void ParseRestFillOrders();
  void ParseRestAccountBalance();
  void ParseRestAccountPosition();

  void ParseWsMessage();

  void ParseRestOrderInfo(const JsonValue& data, ProductOrderElement* product_order_element);
  bool ParseRestFillInfo(const JsonValue& data, ProductFillBundle* product_fill_bundle);
  void ParseBalanceFromWs(const JsonValue& data);
  void ParseOrderFromWs(const JsonValue& data);
  void ParseTradeFromWs(const JsonValue& data);
  void ParsePositionFromWs(const JsonValue& data);

  bool ParseRawPosition(const JsonValue& doc, RawPositionMap* raw_position_map);

  bool IsCryptoFuturesErrMessage(const JsonValue& data) const;
  OrderSide GetOrderSide(std::string_view side) const;
  OrderType GetOrderType(std::string_view type) const;
  void SetOrderStatus(const JsonValue& data, ProductOrderElement* product_order_element) const;
  inline auto GetNativeCurrency(std::string_view currency_str) -> std::string {
    if (currency_str == "USD_Stable_Coin") {
      return "USD";
    } else {
      return currency_str.data();
    }
  }

 private:
  bool is_account_balance_initialized_ = false;
  bool is_account_position_initialized_ = false;
};

}  // namespace coin2::exchange::crypto::order_futures
